/////////////////////////////////////////////////////////////////////////////////////////////
///<Filename>  		EventSystem.cpp		<\Filename>
///<Date>      		09/26/2011			<\Date>      
///<Author>   		Richard A. Small	<\Author>   
///<Purpose>   	
///		Defines the EventSystem Class
///<\Purpose>
/////////////////////////////////////////////////////////////////////////////////////////////
#include "EventSystem.h"

/// <Summary> The instance of this class </Summary>
EventSystem* EventSystem::instance = NULL;


////////////////////////////////////////////////////////////////////////////////////////////////////
/// <Summary>	Gets the instance of this class </Summary>
///
/// <Return>	The instance of this class </Return>
////////////////////////////////////////////////////////////////////////////////////////////////////
EventSystem& EventSystem::GetInstance()
{
	if(NULL == instance)
	{
		instance = new EventSystem;
	}
	return *instance;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// <Summary>	Deletes the instance of this class </Summary>
////////////////////////////////////////////////////////////////////////////////////////////////////
void EventSystem::DeleteInstance()
{
	SAFE_DELETE(instance);
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// <Summary>	Initializes the event manager </Summary>
////////////////////////////////////////////////////////////////////////////////////////////////////
void EventSystem::Initialize()
{
	for(int i = 0; i < NUM_OF_EVENT_QUEUES; ++i)
	{
		currentEvents[i].Reserve(10);
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// <Summary>	Shuts down the event manager </Summary>
////////////////////////////////////////////////////////////////////////////////////////////////////
void EventSystem::Shutdown()
{
	for(unsigned i = 0; i < NUM_OF_EVENT_QUEUES; ++i)
	{
		const unsigned int size = currentEvents[i].GetSize();
		for(unsigned j = 0; j < size; ++j)
		{
			((StackFactory<void>*)registeredEvents[currentEvents[i][j]->GetEventID().GetIdentity()])->DeleteObject(currentEvents[i][j]);
		}

		currentEvents[currentList].Clear();
	}

	UnRegisterAll();

	for(EventRegisterMap::Iterator iter(registeredEvents); !iter.End(); ++iter)
	{
		delete (*iter).data;
	}

	registeredEvents.Clear();
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// <Summary>	Registers a new listener to the event system </Summary>
///
/// <Param name="listener">	The listener to be added </Param>
/// <Param name="eventID"> 	Identifier for the event to be listened for  </Param>
////////////////////////////////////////////////////////////////////////////////////////////////////
void EventSystem::RegisterClient(IEventListener* listener, const HashString& eventID)
{
	currentListeners[eventID.GetIdentity()].Push_Front(listener);
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// <Summary>	Unregister a listener from the event system </Summary>
///
/// <Param name="listener">	The listener to be removed </Param>
/// <Param name="eventID"> 	Identifier for the event to stop listening for </Param>
////////////////////////////////////////////////////////////////////////////////////////////////////
void EventSystem::UnRegisterClient(IEventListener* listener, const HashString& eventID)
{
	bool done = false;

	for(ListenerMap::Iterator iter(currentListeners); !iter.End(); ++iter)
	{
		if(done)
			break;

		for(SLList<IEventListener*>::Iterator liter((*iter).data); !liter.End(); ++liter)
		{
			if((*liter) == listener)
			{
				(*iter).data.Erase(liter);
				done = true;
				break;
			}
		}
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// <Summary>	Unregister all listeners for all events </Summary>
////////////////////////////////////////////////////////////////////////////////////////////////////
void EventSystem::UnRegisterAll()
{
	currentListeners.Clear();
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// <Summary>	Sends an event </Summary>
///
/// <Param name="eventData">	The event to be processed	</Param>
////////////////////////////////////////////////////////////////////////////////////////////////////
void EventSystem::SendEvent(IEvent* eventData)
{
	currentEvents[currentList].Push_Back(eventData);
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// <Summary>	
/// 	Process all current events and sends them out to all listeners expecting them
/// </Summary>
////////////////////////////////////////////////////////////////////////////////////////////////////
void EventSystem::Update(float delta)
{
	const int listToProcess = currentList;

	currentList = (currentList + 1) % NUM_OF_EVENT_QUEUES;
	ClearEvents();

	for(unsigned i = 0; i < currentEvents[listToProcess].GetSize(); ++i)
	{
		SLList<IEventListener*>::Iterator iter(currentListeners[currentEvents[listToProcess][i]->GetEventID().GetIdentity()]);

		for(; !iter.End(); ++iter)
		{
			(*iter)->HandleEvent(currentEvents[listToProcess][i]);
		}
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// <Summary>	Clears all events from the current queue </Summary>
////////////////////////////////////////////////////////////////////////////////////////////////////
void EventSystem::ClearEvents(void)
{
	const unsigned int size = currentEvents[currentList].GetSize();
	for(unsigned i = 0; i < size; ++i)
	{
		((StackFactory<void>*)registeredEvents[currentEvents[currentList][i]->GetEventID().GetIdentity()])->DeleteObject(currentEvents[currentList][i]);
	}

	currentEvents[currentList].Clear();
}


